package org.amos.filestorage.platform.s3;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.qiniu.common.QiniuException;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.amos.filestorage.exception.FileStorageException;
import org.amos.filestorage.platform.AbstractFilePlatform;
import org.amos.filestorage.platform.config.s3.QiniuFilePlatformConfig;
import org.junit.internal.Throwables;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Objects;
import java.util.function.Consumer;

/**
 * 七牛云 存储
 */
public class QiniuFilePlatform extends AbstractFilePlatform<QiniuFilePlatformConfig> {

    private QiniuClient client;

    public QiniuFilePlatform(String id, QiniuFilePlatformConfig config) {
        super(id, config);
    }

    @Override
    public void initClient() {
        client = new QiniuClient(config.getAccessKey(), config.getSecretKey(), config.getRegion());
    }

    @Override
    public String upload(byte[] bytes, String path, String type) {
        try {
            UploadManager uploadManager = client.getUploadManager();
            String token = client.getAuth().uploadToken(config.getBucket());
            uploadManager.put(new ByteArrayInputStream(bytes), path, token, null, type);
            return StrUtil.format("{}/{}", config.getDomain(), path);
        } catch (IOException e) {
            throw new FileStorageException(Throwables.getStacktrace(e));
        }
    }

    @Override
    public Boolean delete(String path) {
        BucketManager manager = client.getBucketManager();
        try {
            delete(manager, path);
        } catch (QiniuException e) {
            throw new FileStorageException(Throwables.getStacktrace(e));
        }
        return Boolean.TRUE;
    }

    public void delete(BucketManager manager, String filename) throws QiniuException {
        try {
            manager.delete(config.getBucket(), filename);
        } catch (QiniuException e) {
            if (!(e.response != null && e.response.statusCode == 612)) {
                throw e;
            }
        }
    }


    @Override
    public Boolean exists(String path) {
        BucketManager manager = client.getBucketManager();
        try {
            com.qiniu.storage.model.FileInfo stat = manager.stat(config.getBucket(), path);
            if (stat != null && stat.md5 != null) return Boolean.TRUE;
        } catch (QiniuException e) {
            throw new FileStorageException("查询文件是否存在失败！" + e.code() + "，" + e.response.toString(), e);
        }
        return Boolean.FALSE;
    }

    @Override
    public void download(String path, Consumer<InputStream> consumer) {
        String url = client.getAuth().privateDownloadUrl(path);
        try (InputStream in = new URL(url).openStream()) {
            consumer.accept(in);
        } catch (IOException e) {
            throw new FileStorageException(org.junit.internal.Throwables.getStacktrace(e));
        }
    }


    @Getter
    @Setter
    public static class QiniuClient {
        private String accessKey;
        private String secretKey;
        private String region;
        private Auth auth;
        private BucketManager bucketManager;
        private UploadManager uploadManager;

        public QiniuClient(String accessKey, String secretKey, String region) {
            this.accessKey = accessKey;
            this.secretKey = secretKey;
            this.region = region;
        }

        public Auth getAuth() {
            if (auth == null) {
                auth = Auth.create(accessKey, secretKey);
            }
            return auth;
        }

        public BucketManager getBucketManager() {
            if (bucketManager == null) {
                bucketManager = new BucketManager(getAuth(), new Configuration(RegionEnum.getRegion(region)));
            }
            return bucketManager;
        }

        public UploadManager getUploadManager() {
            if (uploadManager == null) {
                uploadManager = new UploadManager(new Configuration(RegionEnum.getRegion(region)));
            }
            return uploadManager;
        }
    }

    @AllArgsConstructor
    @Getter
    public enum RegionEnum {
        huadong("huadong", Region.huadong()),
        huabei("huabei", Region.huabei()),
        beimei("beimei", Region.beimei()),
        xinjiapo("xinjiapo", Region.xinjiapo());
        /**
         * region标识
         */
        private final String code;
        /**
         * Region
         */
        private final Region region;

        public static Region getRegion(String code) {
            Region resultRegion = ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()).getRegion();
            if (Objects.isNull(resultRegion)) {
                return Region.autoRegion();
            }
            return resultRegion;
        }
    }
}
